/**********************************************************************************************
* 版    权：上海金智晟东电力科技有限公司南京分公司
* 项目名称：
* 产品名称：
* 创建日期：2023年03月17日
* 创 建 人：zzg
* 文 件 名：myiic.c
* 文件功能：
* 修 改 者：							日期：
* 备    注：
***********************************************************************************************/
#include "myiic.h"
#include "csg_libopt.h"
#include "csg_sdk_hal.h"
#include "mytypes.h"
//#include "os_lite.h"

#ifdef INCLUDE_SOFT_IIC

uint32_t g_i2c_sem = 0;			//IIC信号量


/**********************************************************************************************
* 函 数 名：void DelayUs(uint16_t nus)
* 功能描述：微秒延迟函数
* 输    入：nus:延迟时间数
* 返    回：
* 设 计 者：zzg								日期：2022年05月26日
* 修 改 者：								日期：
***********************************************************************************************/
void DelayUs(uint16_t nus)
{
	uint32_t i;
	for(i=0; i<nus*14; i++)
	{
		asm("nop");
	}
}

/**********************************************************************************************
* 函 数 名：void IicStart(void)
* 功能描述：IIC开始信号函数
* 输    入：
* 返    回：
* 设 计 者：zzg								日期：2022年05月26日
* 修 改 者：								日期：
***********************************************************************************************/
void IicStart(void)
{
	SDA_OUT();
	IIC_SDA(1);
	IIC_SCL(1);
	DelayUs(4);
	IIC_SDA(0);		//START:when CLK is high,DATA change form high to low 
	DelayUs(4);
	IIC_SCL(0);		//钳住IIC总线，准备发送或接收数据
}

/**********************************************************************************************
* 函 数 名：void IicStop(void)
* 功能描述：IIC停止信号函数
* 输    入：
* 返    回：
* 设 计 者：zzg								日期：2022年05月26日
* 修 改 者：								日期：
***********************************************************************************************/
void IicStop(void)
{
	SDA_OUT();
	IIC_SDA(0);
	IIC_SCL(1);
	DelayUs(2);
	IIC_SDA(1);
	DelayUs(2);
}
/**********************************************************************************************
* 函 数 名：uint8_t IicWaitAck(void)
* 功能描述：IIC等待应答校验函数
* 输    入：
* 返    回：0：正常		1：异常
* 设 计 者：zzg								日期：2022年05月26日
* 修 改 者：								日期：
***********************************************************************************************/
uint8_t IicWaitAck(void)
{
	uint16_t Err_tim=0;
	
	SDA_IN();
	IIC_SDA(1);
	DelayUs(2);
	IIC_SCL(1);
	DelayUs(2);
	while(SDA_READ)
	{
		Err_tim++;
		if(Err_tim > 250)
		{
			IicStop();
			return 1;
		}
	}
	IIC_SCL(0);
	return 0;	
}

/**********************************************************************************************
* 函 数 名：void IicAck(void)
* 功能描述：IIC产生ACK应答函数
* 输    入：
* 返    回：
* 设 计 者：zzg								日期：2022年05月26日
* 修 改 者：								日期：
***********************************************************************************************/
void IicAck(void)
{
	IIC_SCL(0);
	SDA_OUT();
	IIC_SDA(0);
	DelayUs(2);
	IIC_SCL(1);
	DelayUs(2);
	IIC_SCL(0);
}

/**********************************************************************************************
* 函 数 名：void IicNack(void)
* 功能描述：IIC不产生ACK应答函数
* 输    入：
* 返    回：
* 设 计 者：zzg								日期：2022年05月26日
* 修 改 者：								日期：
***********************************************************************************************/
void IicNack(void)
{
	IIC_SCL(0);
	SDA_OUT();
	IIC_SDA(1);
	DelayUs(2);
	IIC_SCL(1);
	DelayUs(2);
	IIC_SCL(0);
}

/**********************************************************************************************
* 函 数 名：void IicSendByte(uint8_t data)
* 功能描述：IIC发送单字节数据
* 输    入：data：待传输数据
* 返    回：
* 设 计 者：zzg								日期：2022年05月26日
* 修 改 者：								日期：
***********************************************************************************************/
void IicSendByte(uint8_t data)
{
	uint8_t i;
	
	SDA_OUT();
	IIC_SCL(0);
	for(i=0; i<8; i++)
	{
		IIC_SDA((data&0x80)>>7);
		data <<= 1;
		DelayUs(2);
		IIC_SCL(1);
		DelayUs(2);
		IIC_SCL(0);
		DelayUs(2);
	}
}

/**********************************************************************************************
* 函 数 名：uint8_t IicReadByte(uint8_t ack)
* 功能描述：IIC读取单字节数据
* 输    入：ack：0:不产生应答标志	1:产生应答标志
* 返    回：
* 设 计 者：zzg								日期：2022年05月26日
* 修 改 者：								日期：
***********************************************************************************************/
uint8_t IicReadByte(uint8_t ack)
{
	uint8_t i,value=0;

	SDA_IN();

	for(i=0; i<8; i++)
	{
		IIC_SCL(0);
		DelayUs(2);
		IIC_SCL(1);
		DelayUs(2);
		value <<= 1;
		if(SDA_READ)
		{
			value++;
		}
		DelayUs(2);
	}
	
	if (!ack)
	{
		IicNack();			//发送nACK
	}
	else
	{
		IicAck();			//发送ACK
	}
	return value;
}

/**********************************************************************************************
* 函 数 名：void IicSemInit(void)
* 功能描述：创建IIC信号量
* 输    入：
* 返    回：
* 设 计 者：zzg								日期：2022年06月09日
* 修 改 者：								日期：
***********************************************************************************************/
void IicSemInit(void)
{
	g_i2c_sem = smMCreate();
	
	if(g_i2c_sem == 0)
	{
		printf("Create iic semphore err\r\n");
	}
}

/**********************************************************************************************
* 函 数 名：int8_t IicSendData(uint8_t *buf, uint8_t id, uint8_t addr, int32_t len)
* 功能描述：IIC发送数据函数
* 输    入：buf:待传输数据指针
* 			id:设备ID
* 			addr:命令字
* 			len:数据长度
* 返    回：
* 设 计 者：zzg								日期：2022年05月27日
* 修 改 者：								日期：
***********************************************************************************************/
int8_t IicSendData(uint8_t *buf, uint8_t id, uint8_t addr, int32_t len)
{
	int32_t i;
	uint8_t *pBuf = buf;
	uint8_t Address = id;
	
	if (g_i2c_sem) 
	{
		smMTake(g_i2c_sem);
	}
	IicStart();
	IicSendByte(Address); 
	if(IicWaitAck() == 1)
	{
		if (g_i2c_sem) 
		{
			smMGive(g_i2c_sem);
		}
		return ERROR;
	}

	IicSendByte(addr); 
	if(IicWaitAck() == 1)
	{
		if (g_i2c_sem) 
		{
			smMGive(g_i2c_sem);
		}
		return ERROR;
	}
	
	for(i=0; i<len; i++)
	{
		IicSendByte(pBuf[i]);
		if(IicWaitAck() == 1)
		{
			if (g_i2c_sem) 
			{
				smMGive(g_i2c_sem);
			}
			return ERROR;
		}
	}
	
	IicStop();
	DelayUs(5);
	
	if (g_i2c_sem) 
	{
		smMGive(g_i2c_sem);
	}
	
	return OK;
}

/**********************************************************************************************
* 函 数 名：int8_t IicReceData(uint8_t *buf, uint8_t id, uint8_t addr, int32_t len)
* 功能描述：IIC接收数据函数
* 输    入：buf:待接收数据指针
* 			id:设备ID
* 			addr:命令字
* 			len:数据长度
* 返    回：
* 设 计 者：zzg								日期：2022年05月27日
* 修 改 者：								日期：
***********************************************************************************************/
int8_t IicReceData(uint8_t *buf, uint8_t id, uint8_t addr, int32_t len)
{
	int32_t i;
	uint8_t *pBuf = buf;
	uint8_t Address = id;
	
	if (g_i2c_sem) 
	{
		smMTake(g_i2c_sem);
	}
	IicStart();
	IicSendByte(Address);
	
	if(IicWaitAck() == 1)
	{
		if (g_i2c_sem) 
		{
			smMGive(g_i2c_sem);
		}
		return ERROR;
	}

	IicSendByte(addr); 
	if(IicWaitAck() == 1)
	{
		if (g_i2c_sem) 
		{
			smMGive(g_i2c_sem);
		}
		return ERROR;
	}
	DelayUs(5);
	
	IicStart();
	IicSendByte(Address|0x01); 
	if(IicWaitAck() == 1)
	{
		if (g_i2c_sem) 
		{
			smMGive(g_i2c_sem);
		}
		return ERROR;
	}

	for(i=0; i<len; i++)
	{
		if(i<len-1)
		{
			pBuf[i] = IicReadByte(1);
		}
		else
		{
			pBuf[i] = IicReadByte(0);
		}
	}
	
	IicStop();
	if (g_i2c_sem) 
	{
		smMGive(g_i2c_sem);
	}
	
	return OK;
}


#else


/**********************************************************************************************
* 函 数 名：void I2C_config(void)
* 功能描述：SPI配置初始化函数
* 输    入：
* 返    回：执行结果
* 设 计 者：zzg								日期：2023年03月18日
* 修 改 者：								日期：
***********************************************************************************************/
void IIC_config(void)
{
	I2C_InitTypeDef init = {0};
	init.clk_div = ((SOC_CLK / I2C1_SPEED) / 5) - 1;
	init.mode = I2C_MASTER_MODE;
	init.scl_pull = ENABLE;
	init.sda_pull = ENABLE;
	I2C_Init(I2C1, &init);
}

/**********************************************************************************************
* 函 数 名：void IIC_ByteWrite(uint8_t slave_addr, uint8_t write_addr, uint8_t* p_buffer)
* 功能描述：IIC发送单字节函数
* 输    入：slave_addr:从机地址 write_addr:写入地址 p_buffer:数据地址
* 返    回：执行结果
* 设 计 者：zzg								日期：2023年03月18日
* 修 改 者：								日期：
***********************************************************************************************/
void IIC_ByteWrite(uint8_t slave_addr, uint8_t write_addr, uint8_t* p_buffer)
{
	uint32_t timeout = 0xFFFFFFFF;
	
	LOS_TaskLock();
	I2C_ACK(I2C1, DISABLE);
	I2C_Start(I2C1);
	I2C_SendSlaveAddr(I2C1, slave_addr, I2C_DIR_WRITE, timeout);
	/* wait until I2C recv ack */
	while (I2C_GetStatus(I2C1, I2C_ACK_STATUS)) {}
	I2C_Write(I2C1, write_addr, timeout);
	/* wait until I2C recv ack */
	while (I2C_GetStatus(I2C1, I2C_ACK_STATUS)) {}
	I2C_Write(I2C1, *p_buffer, timeout);
	/* wait until I2C recv ack */
	while (I2C_GetStatus(I2C1, I2C_ACK_STATUS)) {}
	I2C_Stop(I2C1);
	
	LOS_TaskUnlock();
}

/**********************************************************************************************
* 函 数 名：void IIC_BuffWrite(uint8_t slave_addr, uint8_t write_addr, uint8_t* p_buffer, uint8_t len)
* 功能描述：IIC发送任意字节函数
* 输    入：slave_addr:从机地址 write_addr:写入地址 p_buffer:发送数据地址 len:发送长度
* 返    回：执行结果
* 设 计 者：zzg								日期：2023年03月18日
* 修 改 者：								日期：
***********************************************************************************************/
void IIC_BuffWrite(uint8_t slave_addr, uint8_t write_addr, uint8_t* p_buffer, uint8_t len)
{
	uint32_t intSave;
	uint32_t timeout = 0xFFFFFFFF;
	
	LOS_TaskLock(); 			// 禁止调度
	
	I2C_ACK(I2C1, DISABLE);
	I2C_Start(I2C1);
	I2C_SendSlaveAddr(I2C1, slave_addr, I2C_DIR_WRITE, timeout);
	/* wait until I2C recv ack */
	while (I2C_GetStatus(I2C1, I2C_ACK_STATUS)) {}
	I2C_Write(I2C1, write_addr, timeout);
	/* wait until I2C recv ack */
	while (I2C_GetStatus(I2C1, I2C_ACK_STATUS)) {}
	/* while there is data to be written */
	while (len--)
	{
		/* send a data byte */
		I2C_Write(I2C1, *p_buffer, timeout);
		/* wait until I2C recv ack */
		while (I2C_GetStatus(I2C1, I2C_ACK_STATUS)) {}
		/* point to the next byte to be written */
		p_buffer++;
	}
	I2C_Stop(I2C1);
	
	LOS_TaskUnlock();					// 恢复调度
}

/**********************************************************************************************
* 函 数 名：void IIC_BuffRead(uint8_t slave_addr, uint8_t read_addr, uint8_t* p_buffer, uint8_t len)
* 功能描述：IIC读取任意字节函数
* 输    入：slave_addr:从机地址 read_addr:读取地址 p_buffer:接收数据地址 len:接收长度
* 返    回：执行结果
* 设 计 者：zzg								日期：2023年03月18日
* 修 改 者：								日期：
***********************************************************************************************/
void IIC_BuffRead(uint8_t slave_addr, uint8_t read_addr, uint8_t* p_buffer, uint8_t len)
{
	uint32_t timeout = 0xFFFFFFFF;
	
	LOS_TaskLock();				// 禁止调度
	
	I2C_ACK(I2C1, DISABLE);
	I2C_Start(I2C1);
	I2C_SendSlaveAddr(I2C1, slave_addr, I2C_DIR_WRITE, timeout);
	/* wait until I2C recv ack */
	while (I2C_GetStatus(I2C1, I2C_ACK_STATUS)) {}
	I2C_Write(I2C1, read_addr, timeout);
	/* wait until I2C recv ack */
	while (I2C_GetStatus(I2C1, I2C_ACK_STATUS)) {}
	I2C_Restart(I2C1);
	I2C_SendSlaveAddr(I2C1, slave_addr, I2C_DIR_READ, timeout);
	/* wait until I2C recv ack */
	while (I2C_GetStatus(I2C1, I2C_ACK_STATUS)) {}
	I2C_ACK(I2C1, ENABLE);
	while (len)
	{
		if(1 == len)
		{
			I2C_ACK(I2C1, DISABLE);
		}
		I2C_Read(I2C1, p_buffer, timeout);
		
		/* point to the next location where the byte read will be saved */
		p_buffer++;
		/* decrement the read bytes counter */
		len--;
	}
	I2C_Stop(I2C1);
	
	LOS_TaskUnlock();					// 恢复调度
}

//void DelayUs(uint16_t nus)
//{
//	uint32_t i;
//	for(i=0; i<nus*14; i++)
//	{
//		asm("nop");
//	}
//}
#endif




